# -*- coding: utf-8 -*-
from django.test import TestCase
from django.contrib.auth.models import User
from django.urls import reverse
from rest_framework.test import APIClient, APITestCase
from rest_framework import status
from rest_framework_simplejwt.tokens import RefreshToken

from .models import Category, Product, Review, Tag, ProductTag


class ModelTestCase(TestCase):
    """模型测试用例"""

    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )

        self.category = Category.objects.create(
            name='测试分类',
            description='这是一个测试分类'
        )

        self.product = Product.objects.create(
            name='测试产品',
            description='这是一个测试产品',
            price=99.99,
            category=self.category,
            status='active',
            stock=10,
            created_by=self.user
        )

    def test_category_str_representation(self):
        """测试分类模型的字符串表示"""
        self.assertEqual(str(self.category), '测试分类')

    def test_product_str_representation(self):
        """测试产品模型的字符串表示"""
        self.assertEqual(str(self.product), '测试产品')

    def test_product_category_relationship(self):
        """测试产品和分类的关系"""
        self.assertEqual(self.product.category, self.category)
        self.assertIn(self.product, self.category.products.all())


class APITestBase(APITestCase):
    """API测试基类"""

    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )

        self.admin_user = User.objects.create_user(
            username='admin',
            email='admin@example.com',
            password='adminpass123',
            is_staff=True
        )

        self.category = Category.objects.create(
            name='测试分类',
            description='测试分类描述'
        )

        self.product = Product.objects.create(
            name='测试产品',
            description='测试产品描述',
            price=99.99,
            category=self.category,
            status='active',
            stock=10,
            created_by=self.user
        )

        # JWT Token
        refresh = RefreshToken.for_user(self.user)
        self.access_token = str(refresh.access_token)

        admin_refresh = RefreshToken.for_user(self.admin_user)
        self.admin_access_token = str(admin_refresh.access_token)

    def authenticate_user(self, user='user'):
        """认证用户"""
        token = self.access_token if user == 'user' else self.admin_access_token
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token}')

    def unauthenticate(self):
        """取消认证"""
        self.client.credentials()


class CategoryAPITestCase(APITestBase):
    """分类API测试"""

    def test_category_list_unauthenticated(self):
        """测试未认证用户获取分类列表"""
        url = reverse('category-list-basic')
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

    def test_category_create_authenticated(self):
        """测试已认证用户创建分类"""
        self.authenticate_user()
        url = reverse('category-list-basic')
        data = {
            'name': '新分类',
            'description': '新分类描述'
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], '新分类')

    def test_category_detail(self):
        """测试获取分类详情"""
        url = reverse('category-detail-basic', args=[self.category.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], '测试分类')


class ProductAPITestCase(APITestBase):
    """产品API测试"""

    def test_product_list(self):
        """测试产品列表"""
        url = reverse('product-list-create')
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('results', response.data)  # 分页响应

    def test_product_create_authenticated(self):
        """测试已认证用户创建产品"""
        self.authenticate_user()
        url = reverse('product-list-create')
        data = {
            'name': '新产品',
            'description': '新产品描述',
            'price': '199.99',
            'category': self.category.id,
            'status': 'active',
            'stock': 5
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], '新产品')

    def test_product_create_unauthenticated(self):
        """测试未认证用户创建产品"""
        url = reverse('product-list-create')
        data = {
            'name': '新产品',
            'description': '新产品描述',
            'price': '199.99',
            'category': self.category.id,
            'status': 'active',
            'stock': 5
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_product_detail(self):
        """测试产品详情"""
        url = reverse('product-detail-generic', args=[self.product.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], '测试产品')


class AuthenticationTestCase(APITestBase):
    """认证测试"""

    def test_jwt_token_obtain(self):
        """测试JWT令牌获取"""
        url = reverse('token_obtain_pair')
        data = {
            'username': 'testuser',
            'password': 'testpass123'
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('access', response.data)
        self.assertIn('refresh', response.data)

    def test_jwt_token_refresh(self):
        """测试JWT令牌刷新"""
        # 先获取令牌
        refresh = RefreshToken.for_user(self.user)

        url = reverse('token_refresh')
        data = {'refresh': str(refresh)}
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('access', response.data)


class SerializerTestCase(APITestBase):
    """序列化器测试"""

    def test_product_serializer_validation(self):
        """测试产品序列化器验证"""
        from .serializers import ProductCreateUpdateSerializer

        # 测试有效数据
        valid_data = {
            'name': '有效产品名',
            'description': '产品描述',
            'price': '99.99',
            'category': self.category.id,
            'status': 'active',
            'stock': 10
        }
        serializer = ProductCreateUpdateSerializer(data=valid_data)
        self.assertTrue(serializer.is_valid())

        # 测试无效数据（名称太短）
        invalid_data = {
            'name': 'AB',  # 少于3个字符
            'description': '产品描述',
            'price': '99.99',
            'category': self.category.id,
            'status': 'active',
            'stock': 10
        }
        serializer = ProductCreateUpdateSerializer(data=invalid_data)
        self.assertFalse(serializer.is_valid())
        self.assertIn('name', serializer.errors)


class PermissionTestCase(APITestBase):
    """权限测试"""

    def test_product_creation_requires_authentication(self):
        """测试产品创建需要认证"""
        url = reverse('product-list-create')
        data = {
            'name': '新产品',
            'description': '产品描述',
            'price': '99.99',
            'category': self.category.id,
            'status': 'active',
            'stock': 10
        }

        # 未认证请求
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

        # 认证后请求
        self.authenticate_user()
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)


# 运行测试的命令：
# python manage.py test api_examples.tests

# 运行特定测试类：
# python manage.py test api_examples.tests.ProductAPITestCase

# 运行特定测试方法：
# python manage.py test api_examples.tests.ProductAPITestCase.test_product_list


class ImageProcessingTestCase(APITestBase):
    """图片处理功能测试"""

    def setUp(self):
        super().setUp()

        # 创建测试图片
        from PIL import Image
        import io
        from django.core.files.uploadedfile import SimpleUploadedFile

        # 生成一个简单的测试图片
        image = Image.new('RGB', (100, 100), color='red')
        image_io = io.BytesIO()
        image.save(image_io, format='JPEG')
        image_io.seek(0)

        self.test_image = SimpleUploadedFile(
            "test_image.jpg",
            image_io.getvalue(),
            content_type="image/jpeg"
        )

    def test_image_upload_authenticated(self):
        """测试已认证用户上传图片"""
        self.authenticate_user()
        url = reverse('product-upload-image', args=[self.product.id])

        data = {'image': self.test_image}
        response = self.client.post(url, data, format='multipart')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('image_url', response.data)

    def test_image_upload_unauthenticated(self):
        """测试未认证用户上传图片"""
        url = reverse('product-upload-image', args=[self.product.id])

        data = {'image': self.test_image}
        response = self.client.post(url, data, format='multipart')

        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_image_info_access(self):
        """测试获取图片信息"""
        # 先上传图片
        self.authenticate_user()
        upload_url = reverse('product-upload-image', args=[self.product.id])
        self.client.post(upload_url, {'image': self.test_image}, format='multipart')

        # 获取图片信息
        info_url = reverse('product-image-info', args=[self.product.id])
        response = self.client.get(info_url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('width', response.data)
        self.assertIn('height', response.data)
        self.assertIn('format', response.data)

    def test_thumbnail_generation(self):
        """测试缩略图生成"""
        # 先上传图片
        self.authenticate_user()
        upload_url = reverse('product-upload-image', args=[self.product.id])
        self.client.post(upload_url, {'image': self.test_image}, format='multipart')

        # 生成缩略图
        thumbnail_url = reverse('product-thumbnail', args=[self.product.id])
        response = self.client.get(thumbnail_url, {'width': 50, 'height': 50})

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response['Content-Type'], 'image/jpeg')
